﻿using System;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.ServiceModel;

namespace Wisdom.Core.WcfExtensions
{
    /// <summary>
    /// 服务真实代理类(泛型类)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    internal class ServiceRealProxy<T> : RealProxy
    {
        private readonly string _endpointName;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="endpointName">终结点名称</param>
        public ServiceRealProxy(string endpointName)
            : base(typeof(T))
        {
            if (string.IsNullOrEmpty(endpointName))
            {
                throw new ArgumentNullException("endpointName");
            }
            this._endpointName = endpointName;
        }
        /// <summary>
        /// 消息调用
        /// </summary>
        /// <param name="msg">通讯数据 类对象</param>
        /// <returns>通讯数据 类对象</returns>
        public override IMessage Invoke(IMessage msg)
        {
            T channel = ChannelFactoryCreator.Create<T>(this._endpointName).CreateChannel();
            var methodCall = (IMethodCallMessage)msg;
            IMethodReturnMessage methodReturn;

            var copiedArgs = new object[methodCall.Args.Length];
            methodCall.Args.CopyTo(copiedArgs, 0);

            try
            {
                var returnValue = methodCall.MethodBase.Invoke(channel, copiedArgs);
                methodReturn = new ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall);
                var communicationObject = channel as ICommunicationObject;
                if (communicationObject != null) communicationObject.Close();
            }
            catch (Exception ex)
            {
                if (ex.InnerException is CommunicationException || ex.InnerException is TimeoutException)
                {
                    var communicationObject = channel as ICommunicationObject;
                    if (communicationObject != null) communicationObject.Abort();
                }

                if (ex.InnerException != null)
                {
                    methodReturn = new ReturnMessage(ex.InnerException, methodCall);
                }
                else
                {
                    methodReturn = new ReturnMessage(ex, methodCall);
                }
            }

            return methodReturn;
        }
    }
}